{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Vector manipulation in Python\n",
    "\n",
    "In this lab, you will have the opportunity to practice once again with the NumPy library. This time, we will explore some advanced operations with arrays and matrices.\n",
    "\n",
    "At the end of the previous module, we used PCA to transform a set of many variables into a set of only two uncorrelated variables. This process was made through a transformation of the data called rotation. \n",
    "\n",
    "In this week's assignment, you will need to find a transformation matrix from English to French vector space embeddings. Such a transformation matrix is nothing else but a matrix that rotates and scales vector spaces.\n",
    "\n",
    "In this notebook, we will explain in detail the rotation transformation. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Transforming vectors\n",
    "\n",
    "There are three main vector transformations:\n",
    "* Scaling\n",
    "* Translation\n",
    "* Rotation\n",
    "\n",
    "In previous notebooks, we have applied the first two kinds of transformations. Now, let us learn how to use a fundamental transformation on vectors called _rotation_.\n",
    "\n",
    "The rotation operation changes the direction of a vector, letting unaffected its dimensionality and its norm. Let us explain with some examples. \n",
    "\n",
    "In the following cells, we will define a NumPy matrix and a NumPy array. Soon we will explain how this is related to matrix rotation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np                     # Import numpy for array manipulation\n",
    "import matplotlib.pyplot as plt        # Import matplotlib for charts\n",
    "from utils_nb import plot_vectors      # Function to plot vectors (arrows)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create a 2 x 2 matrix\n",
    "R = np.array([[2, 0],\n",
    "              [0, -2]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([[1, 1]]) # Create a 1 x 2 matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The dot product between a vector and a square matrix produces a rotation and a scaling of the original vector. \n",
    "\n",
    "Remember that our recommended way to get the dot product in Python is np.dot(a, b):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 2, -2]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = np.dot(x, R) # Apply the dot product between x and R\n",
    "y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are going to use Pyplot to inspect the effect of the rotation on 2D vectors visually. For that, we have created a function `plot_vectors()` that takes care of all the intricate parts of the visual formatting. The code for this function is inside the `utils_nb.py` file. \n",
    "\n",
    "Now we can plot the vector $\\vec x = [1, 1]$ in a cartesian plane. The cartesian plane will be centered at `[0,0]` and its x and y limits will be between `[-4, +4]`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_vectors([x], axes=[4, 4], fname='transform_x.svg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, let's plot in the same system our vector $\\vec x = [1, 1]$ and its dot product with the matrix\n",
    "\n",
    "$$Ro = \\begin{bmatrix} 2 & 0 \\\\ 0 & -2 \\end{bmatrix}$$\n",
    "\n",
    "$$y = x \\cdot Ro = [[-2, 2]]$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_vectors([x, y], axes=[4, 4], fname='transformx_and_y.svg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the output vector `y` (blue) is transformed in another vector. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 2\n",
    "\n",
    "We are going to use Pyplot to inspect the effect of the rotation on 2D vectors visually. For that, we have created a function that takes care of all the intricate parts of the visual formatting. The following procedure plots an arrow within a Pyplot canvas.\n",
    "\n",
    "Data that is composed of 2 real attributes is telling to belong to a $ RxR $ or $ R^2 $ space. Rotation matrices in $R^2$ rotate a given vector $\\vec x$ by a counterclockwise angle $\\theta$ in a fixed coordinate system. Rotation matrices are of the form:\n",
    "\n",
    "$$Ro = \\begin{bmatrix} cos \\theta & -sin \\theta \\\\ sin \\theta & cos \\theta \\end{bmatrix}$$\n",
    "\n",
    "The trigonometric functions in Numpy require the angle in radians, not in degrees. In the next cell, we define a rotation matrix that rotates vectors by $45^o$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Rotation matrix\n",
      "[[-0.17364818 -0.98480775]\n",
      " [ 0.98480775 -0.17364818]]\n",
      "\n",
      "Rotated vector\n",
      "[[ 1.62231915 -2.31691186]]\n",
      "\n",
      " x2 norm 2.8284271247461903\n",
      "\n",
      " y2 norm 2.82842712474619\n",
      "\n",
      " Rotation matrix norm 1.414213562373095\n"
     ]
    }
   ],
   "source": [
    "angle = 100 * (np.pi / 180) #convert degrees to radians\n",
    "\n",
    "Ro = np.array([[np.cos(angle), -np.sin(angle)],\n",
    "              [np.sin(angle), np.cos(angle)]])\n",
    "\n",
    "x2 = np.array([2, 2]).reshape(1, -1) # make it a row vector\n",
    "y2 = np.dot(x2, Ro)\n",
    "\n",
    "print('Rotation matrix')\n",
    "print(Ro)\n",
    "print('\\nRotated vector')\n",
    "print(y2)\n",
    "\n",
    "print('\\n x2 norm', np.linalg.norm(x2))\n",
    "print('\\n y2 norm', np.linalg.norm(y2))\n",
    "print('\\n Rotation matrix norm', np.linalg.norm(Ro))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_vectors([x2, y2], fname='transform_02.svg')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some points to note:\n",
    "\n",
    "* The norm of the input vector is the same as the norm of the output vector. Rotations matrices do not modify the norm of the vector, only its direction.\n",
    "* The norm of any $R^2$ rotation matrix is always $\\sqrt 2 = 1.414221$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Frobenius Norm\n",
    "\n",
    "The Frobenius norm is the generalization to $R^2$ of the already known norm function for vectors \n",
    "\n",
    "$$\\| \\vec a \\| = \\sqrt {{\\vec a} \\cdot {\\vec a}} $$\n",
    "\n",
    "For a given $R^2$ matrix A, the frobenius norm is defined as:\n",
    "\n",
    "$$\\|\\mathrm{A}\\|_{F} \\equiv \\sqrt{\\sum_{i=1}^{m} \\sum_{j=1}^{n}\\left|a_{i j}\\right|^{2}}$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[2, 2],\n",
    "              [2, 2]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`np.square()` is a way to square each element of a matrix. It must be equivalent to use the * operator in Numpy arrays."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4, 4],\n",
       "       [4, 4]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A_squared = np.square(A)\n",
    "A_squared"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now you can sum over the elements of the resulting array, and then get the square root of the sum."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4.0"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A_Frobenius = np.sqrt(np.sum(A_squared))\n",
    "A_Frobenius"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That was the extended version of the `np.linalg.norm()` function. You can check that it yields the same result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Frobenius norm of the Rotation matrix\n",
      "1.414213562373095 ==  1.414213562373095\n"
     ]
    }
   ],
   "source": [
    "print('Frobenius norm of the Rotation matrix')\n",
    "print(np.sqrt(np.sum(Ro * Ro)), '== ', np.linalg.norm(Ro))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Congratulations!! We've covered a few more matrix operations in this lab. This will come in handy in this week's programming assignment!**"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  },
  "nbTranslate": {
   "displayLangs": [
    "*"
   ],
   "hotkey": "alt-t",
   "langInMainMenu": true,
   "sourceLang": "en",
   "targetLang": "fr",
   "useGoogleTranslate": true
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
